﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using SimpleRest.Core.Extensions.Documentation;
using SimpleRest.Core.Routing;

namespace SimpleRest.Core.Extensions.Media
{
    [GeneralDescription("Json media type support.")]
    public class JsonMediaTypeFormatter : IMediaTypeFormatter
    {
        public bool IsMediaFormatted { get; set; }

        public IEnumerable<string> SupportedMediaTypes
        {
            get
            {
                return new List<string>()
                {
                    "application/json",
                    "application/x-javascript",
                    "text/javascript",
                    "text/json",
                    "text/x-javascript",
                    "text/x-json"
                };
            }
        }

        public Stream Serialize(object obj)
        {
            string val = null;
            if (this.IsMediaFormatted)
                val = Newtonsoft.Json.JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.Indented);
            else
                val = Newtonsoft.Json.JsonConvert.SerializeObject(obj);

            return new MemoryStream(System.Text.Encoding.UTF8.GetBytes(val));
        }

        public object DeSerialize(Stream stream, Type type)
        {
            if (stream == null || stream.Length == 0 || type == null)
                return null;

            System.IO.Stream str; String strmContents;
            Int32 counter, strLen, strRead;
            // Create a Stream object.
            str = stream;
            // Find number of bytes in stream.
            strLen = Convert.ToInt32(str.Length);
            // Create a byte array.
            byte[] strArr = new byte[strLen];
            // Read stream into byte array.
            strRead = str.Read(strArr, 0, strLen);

            if (strArr.Length == 0)
                return null;

            return Newtonsoft.Json.JsonConvert.DeserializeObject(System.Text.Encoding.UTF8.GetString(strArr), type);
        }

        private static byte[] ReadToEnd(System.IO.Stream stream)
        {
            long originalPosition = 0;

            if (stream.CanSeek)
            {
                originalPosition = stream.Position;
                stream.Position = 0;
            }

            try
            {
                byte[] readBuffer = new byte[stream.Length];

                int totalBytesRead = 0;
                int bytesRead;

                while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
                {
                    totalBytesRead += bytesRead;

                    if (totalBytesRead == readBuffer.Length)
                    {
                        int nextByte = stream.ReadByte();
                        if (nextByte != -1)
                        {
                            byte[] temp = new byte[readBuffer.Length * 2];
                            Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                            Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                            readBuffer = temp;
                            totalBytesRead++;
                        }
                    }
                }

                byte[] buffer = readBuffer;
                if (readBuffer.Length != totalBytesRead)
                {
                    buffer = new byte[totalBytesRead];
                    Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
                }
                return buffer;
            }
            finally
            {
                if (stream.CanSeek)
                {
                    stream.Position = originalPosition;
                }
            }
        }

        public bool CanSerialize(Type type)
        {
            if (type == null) return true;
            return true;
        }

        public bool CanDeserialize(Type type)
        {
            if (type == null) return true;
            return true;
        }
    }
}
